package operator

/**
 * 1.位运算不是直接对操作数的二进制的原码进行运算,而是对操作数的二进制补码进行算，因为内存中的数据以补码形式存在。
 *
 * 2.位运算的步骤：
 *       a.写出十进制操作数的补码。
 *       b.对补码进行位运算，得到目标结果的补码。
 *       c.将目标的补码，还原成目标的十进制值。
 *
 *
 * 3. 原码、反码和补码：
 *      a.正数的反码和补码与其原码相同.
 *      b.负数的反码为其原码除符号位外各位取反。
 *      c.负数的补码为其反码+1。
 *
 * 4. 进行移位运算时，还要遵循一下规则：
 *      a. 对于Int类型的整数移位 A shl B ,当B>32时，系统会先用B对32求余（因为Int类型只有32位），得到的结果才是真正移位的位数。
 *      b. 对于Long类型的整数移位 A shl B ,当B>64时，系统会先用B对64求余（因为Int类型只有64位），得到的结果才是真正移位的位数。
 */
fun main(args: Array<String>) {
    //按位与：当两位同时为1时才返回1
    //5 和 9 按位与 =1
    println("5 and 9 =${5 and 9}")

    /*
      -5的补码：11111111 11111111 11111111 11111011
      -9的补码：11111111 11111111 11111111 11110111
      //按位与得到目标的补码
    目标的补码： 11111111 11111111 11111111 11110011
    目标的反码： 11111111 11111111 11111111 11110010
    目标的原码： 10000000 00000000 00000000 00001101

     -5 和 -9 按位与 = -（2^3+2^2+2^0）=-(8+4+1) =-13

     */
    //-5 和 -9 按位与 =-13
    println("-5 and -9 =${-5 and -9}")
    //按位或：当两位中有一位是1，就返回1
    //5 和 9按位或 =13
    println("5 or 9 =${5 or 9}")
    /*
       5的原码：       00000000 00000000 00000000 00000101
       //整数的反码和补码与其原码相同,
       5的反码：       00000000 00000000 00000000 00000101
       5的补码：       00000000 00000000 00000000 00000101
       //5的补码进行按位非得到目标的补码,按位非：将操作数的每个位（包括符号位）全部取反
       目标的补码：     11111111 11111111 11111111 11111010
       //目标（负数）的反码为补码-1
       目标的反码：     11111111 11111111 11111111 11111001
       //负数的反码为对该数的原码除符号位外各位取反。反码反向操作得到原码
       目标的原码：     10000000 00000000 00000000 00000110

       目标转换成十进制为：   -（2^2+2^1）= -6
     */
    //5的按位非是6
    println("5.inv()=${5.inv()}")

    /*
   -5的原码：       10000000 00000000 00000000 00000101
   //负数的反码为对该数的原码除符号位外各位取反
   -5的反码：       11111111 11111111 11111111 11111010
   //负数的补码为反码+1
   -5的补码：       11111111 11111111 11111111 11111011
   //-5的补码进行按位非得到目标的补码,按位非：将操作数的每个位（包括符号位）全部取反
   目标的补码：     00000000 00000000 00000000 00000100
   //目标（正数）的反码与补码和原码相同
   目标的反码：     00000000 00000000 00000000 00000100
   //负数的反码为对该数的原码除符号位外各位取反。反码反向操作得到原码
   目标的原码：     00000000 00000000 00000000 00000100

   目标转换成十进制为：   2^2= 4
 */
    //-5的按位非是4
    println("-5.inv()=${(-5).inv()}")

    //按位异或：当两位相同时返回0，否则返回1
    //5 和 9 按位异或 =12
    println("5 xor 9 =${5 xor 9}")


    //左移运算：将操作数的二进制编码整体左移指定位数，左移后右边空出来的位以0补充
    /*
      5的原码：       00000000 00000000 00000000 00000101
      //正数的反码和补码与其原码相同
      5的反码：       00000000 00000000 00000000 00000101
      5的补码：       00000000 00000000 00000000 00000101
      //5的补码进行左移两位得到目标的补码
      目标的补码：     00000000 00000000 00000000 00010100
      //正数的补码与反码和原码相同
      目标的反码：     00000000 00000000 00000000 00010100
      目标的原码：     00000000 00000000 00000000 00010100

       目标转换成十进制为：   2^4+2^2= 20
    */
    //5 左移两位 =20
    println("5 shl 2=${5 shl 2}")

    /*
      -5的原码：       10000000 00000000 00000000 00000101
      //负数的反码为对该数的原码除符号位外各位取反
      -5的反码：       11111111 11111111 11111111 11111010
      //负数的补码为其反码+1
      -5的补码：       11111111 11111111 11111111 11111011
      //-5的补码进行左移两位得到目标的补码
      目标的补码：      11111111 11111111 11111111 11111100
      //负数的反码为其补码-1
      目标的反码：      11111111 11111111 11111111 11101011
      //负数的反码为对该数的原码除符号位外各位取反。反码反向操作得到原码
      目标的原码：      10000000 00000000 00000000 00010100

       目标转换成十进制为：   -(2^4+2^2)= -20
    */
    //-5 左移两位 =-20
    println("-5 shl 2=${-5 shl 2}")


    //右移运算：把第一个数的二进制编码右移指定位数后，左边空出来的位以原来的符号位填充，即如果第一个操作数原来是正数，
    //则左边补0，如果第一个操作数是负数，测左边补1。
    //5 右移两位 =1
    println("5 shr 2=${5 shr 2}")

    /*
      -5的原码：       10000000 00000000 00000000 00000101
      //负数的反码为对该数的原码除符号位外各位取反
      -5的反码：       11111111 11111111 11111111 11111010
      //负数的补码为其反码+1
      -5的补码：       11111111 11111111 11111111 11111011
      //-5的补码进行右移两位得到目标的补码
      目标的补码：      11111111 11111111 11111111 11111110
      //负数的反码为其补码-1
      目标的反码：      11111111 11111111 11111111 11111101
      //负数的反码为对该数的原码除符号位外各位取反。反码反向操作得到原码
      目标的原码：      10000000 00000000 00000000 00000010

       目标转换成十进制为：   -(2^1)= -2
    */
    //-5 右移两位 =-2
    println("-5 shr 2=${(-5) shr 2}")
    //无符号右移运算：把第一个数的二进制编码右移指定位数后，左边空出来的位总是以0填充。
    //5 无符号右移两位 =1
    println("5 ushr 2=${5 ushr 2}")
    //-5 无符号右移两位 =1073741822
    println("-5 ushr 2=${-5 ushr 2}")


}